package zero.tech.wsnet.net;

import java.util.HashMap;
import java.util.Map;

import javax.websocket.Session;

import com.alibaba.fastjson.JSONObject;

import zero.tech.core.ZeroContext;
import zero.tech.core.data.Resp;
import zero.tech.core.data.RespCode;
import zero.tech.core.event.service.api.EventService;
import zero.tech.core.util.EngineLogUtil;
import zero.tech.core.util.StringHelper;
import zero.tech.core.work.WorkManager;
import zero.tech.wsnet.common.ReqProcess;
import zero.tech.wsnet.common.ReqProcessManager;
import zero.tech.wsnet.common.ReqQueueProcess;
import zero.tech.wsnet.controller.Controller;
import zero.tech.wsnet.data.CMD;
import zero.tech.wsnet.data.Consts;
import zero.tech.wsnet.data.Message;
import zero.tech.wsnet.data.NetEventType;

public class WebClient {
	private Session session;
	private String sessionId;
	private final Map<String, Object> attributes = new HashMap<String, Object>();
	private Controller controller;
	private String userId;

	public WebClient(Session session,String userId) {
		this.userId=userId;
		if (session != null) {
			this.session = session;
			this.sessionId = session.getId();
			session.getUserProperties().put(Consts.SESSION_PK_WEBCLIENT, this);
		}else {
			this.sessionId=StringHelper.randUUID();
		}
	}

	public Map<String, Object> getAttributes() {
		return attributes;
	}

	public Controller getController() {
		return controller;
	}

	public void setController(Controller controller) {
		this.controller = controller;
	}


	public Session getSession() {
		return session;
	}

	public void setSession(Session session) {
		this.session = session;
	}

	public String getSessionId() {
		return sessionId;
	}

	public void setSessionId(String sessionId) {
		this.sessionId = sessionId;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	/**
	 * 实现服务器主动推送
	 */
	public void sendMessage(String handle,Resp resp) {
		Message out=Message.build(handle, resp);
		sendMessage(out);
	}
	
	
	/**
	 * 实现服务器主动推送
	 */
	public void sendMessage(Message out) {
		String msg = JSONObject.toJSONString(out);
		synchronized (this) {
			if(session!=null&&session.isOpen()){
				if(!out.getHandle().equals("res_heart_beat")) {
					System.out.println("服务器发送:"+msg);
				}
				try {
					session.getBasicRemote().sendText(msg);
				} catch (Exception e) {
					EngineLogUtil.traceFull(e);
				}
			}
		}
	}

	/**
	 * 服务器主动关闭连接
	 */
	public void activeClose() {
		if (session!=null&&session.isOpen()) {
			sendMessage(Message.build(CMD.COMMON_KICK_OUT, Resp.build(RespCode.OK, "被T出连接")));
			close();
		} 
	}

	public void setAttribute(String attribute, Object val) {
		attributes.put(attribute, val);
	}

	public Object getAttribute(String attribute) {
		return this.attributes.get(attribute);
	}

	public void close() {
		CacheClient.remove(this);
	}

	public void open() {
		setAttribute(Consts.LAST_RECEIVE_PACK_TIME, System.currentTimeMillis());
		CacheClient.add(this);
		sendMessage(Message.build(CMD.COMMON_SESSION_OPEN, Resp.build(RespCode.OK, "连接打开")));
		EventService netEventService = ZeroContext.getInstance(EventService.class);
		netEventService.engineNotify(NetEventType.ENGINE_WEBSOCKET_OPEN, this);
	}

	public void receive(String message) {
		setAttribute(Consts.LAST_RECEIVE_PACK_TIME, System.currentTimeMillis());
		Message in= JSONObject.parseObject(message, Message.class);
		if(!in.getHandle().equals("req_heart_beat")) {
			System.out.println("收到客户端消息:"+message);
		}
		String code = in.getHandle();
		Class<?> clz = ReqProcessManager.getManager().getProcess(code);
		if (clz == null) {
			// 找不到处理器
			sendMessage(Message.build(CMD.COMMON_NO_PROCESS_EXIST,
					Resp.build(RespCode.SERVER_ERROR, "消息号" + code + "找不到处理器")));
		} else {
			try {
				Object process = clz.newInstance();
				if (process instanceof ReqProcess) {
					ReqProcess net = (ReqProcess) process;
					net.init(in, this);
					net.run();
				} else if (process instanceof ReqQueueProcess) {
					ReqQueueProcess net = (ReqQueueProcess) process;
					net.init(in, this);
					WorkManager.getManager().submit(net);
				}
			} catch (Exception e) {
				EngineLogUtil.traceFull(e);
			}
		}
	}

	public boolean isAlive() {
		return session!=null&&session.isOpen();
	}
}
